package cn.qdhlm.collectservice.core.component.analyse;

import cn.qdhlm.collectservice.common.Constant;
import cn.qdhlm.collectservice.common.util.CodeUtil;
import cn.qdhlm.collectservice.common.util.ComUtil;
import cn.qdhlm.collectservice.core.component.Checker;
import cn.qdhlm.collectservice.core.component.Commander;
import cn.qdhlm.collectservice.model.rocketmq.TerminalData;
import cn.qdhlm.collectservice.service.UtilityService;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Name: AnyAfn0c
 * @Description: 控制（AFN=0CH）
 * @Author: jiangcs
 */
@Log4j2
@Component
public class AnyAfn0c {
    @Autowired
    private Commander commander;
    @Autowired
    private UtilityService utilityService;

    public boolean execute(int fn, int sn, ByteBuf byteBuf, TerminalData terminalData) {
        Map<String, Object> resultMap = null;

        switch (fn) {
            // F1：透传数据格式
            case 1:
                // 数据包长度
                int packageLength = byteBuf.readShortLE();
                if (packageLength <= 0) {
                    log.warn("execute: packageLength <= 0");
                } else {
                    // 2: 1-CS；1-16
                    int actualPackageLength = byteBuf.readableBytes() - 2;
                    if (packageLength != actualPackageLength) {
                        log.error("execute: packageLength[{}] not equal actualPackageLength[{}]", packageLength, actualPackageLength);
                    } else {
                        // 截取 透传数据包
                        ByteBuf byteBufData = byteBuf.copy(byteBuf.readerIndex(), packageLength);

                        log.info("execute: packageLength[{}], byteBufData[{}]", packageLength, ByteBufUtil.hexDump(byteBufData));

                        boolean checkFlag = Checker.checkTransparent(byteBufData);
                        if (checkFlag) {
                            // 跳过1个字节：起始字符
                            byteBufData.skipBytes(1);
                            // 仪表类型：46-智能调节阀
                            String deviceType = CodeUtil.byteToHexString(byteBufData.readByte());
                            // 跳过 7个字节：地址域
                            byteBufData.skipBytes(7);
                            // 控制码
                            String controlCode = CodeUtil.byteToHexString(byteBufData.readByte());
                            // 数据长度
                            int dataLength = byteBufData.readByte();

                            log.info("execute: deviceType[{}], controlCode[{}], dataLength[{}]", deviceType, controlCode, dataLength);

                            // 处理数据
                            resultMap = processTransparentData(byteBufData,terminalData.getTerminalId(), terminalData.getProtocolCode());
                        }
                    }
                }
                break;
            case 3:
            case 4:
            case 5:
                resultMap = new HashMap<>(1);

                // 更新命令结果状态
                resultMap.put("statusCode", Constant.SYMBOL_00);
                break;
            case 6:
                // 下发读供暖期命令

                String commandTerminalId = commander.execute("0c", "7", null);

                resultMap = new HashMap<>(2);
                resultMap.put("commandTerminalId", commandTerminalId);

                // 更新命令结果状态
                resultMap.put("statusCode", Constant.SYMBOL_00);
                break;
            case 7:
                resultMap = new HashMap<>(3);

                // 采暖季开始
                String startMonth = CodeUtil.byteToHexString(byteBuf.readByte());
                String startDay = CodeUtil.byteToHexString(byteBuf.readByte());
                resultMap.put("heatSeasonStart", startMonth + "-" + startDay);
                // 采暖季结束
                String endMonth = CodeUtil.byteToHexString(byteBuf.readByte());
                String endDay = CodeUtil.byteToHexString(byteBuf.readByte());
                resultMap.put("heatSeasonEnd", endMonth + "-" + endDay);

                // 保存终端配置参数
//                utilityService.saveTerminalNBConfigParam4HeatSeason(terminalVO.getId(), resultMap);

                // 更新命令结果状态
                resultMap.put("statusCode", Constant.SYMBOL_00);
                break;
            default:
                log.error("execute: fn[{}] match fail", fn);
        }

        // 执行结果
        boolean executeFlag = resultMap != null;

        // 更新命令结果、状态
//        utilityService.updateCommandResultAndStatus(terminalVO.getTerminalNo(), sn, resultMap, executeFlag ? 2 : 3);

        return executeFlag;
    }

    private Map<String, Object> processTransparentData(ByteBuf byteBuf, Integer terminalId, String protocolCode) {
        Map<String, Object> resultMap;

        // 数据标识
        String dataSymbol = CodeUtil.shortToHexString(byteBuf.readShort());
        // 序列号
        int sn = byteBuf.readUnsignedByte();

        log.info("processData: terminalId[{}], dataSymbol[{}], sn[{}]", terminalId, dataSymbol, sn);

        String cleanCycleLow, cleanCycleHigh, startMonth, startDay, endMonth, endDay, openDegreeUpperLow, openDegreeUpperHigh, openDegreeLowerLow, openDegreeLowerHigh;

        switch (dataSymbol) {
            // 调节阀+锁闭阀: 写阀门控制（A0/17）
            case "a017":
                resultMap = new HashMap<>(2);
                resultMap.put("state", CodeUtil.shortToHexString(byteBuf.readShortLE()));

                // 更新命令结果状态
                resultMap.put("statusCode", Constant.SYMBOL_00);
                break;
            // 调节阀+锁闭阀: 写清洗阀门周期（A0/2C）
            case "a02c":
                // 客户AC/01
                // 调节阀: 写调节阀所有配置参数
                // NBT200测温插座: 设置温度偏差
            case "ac01":
                // 调节阀: 写是否启用温差、回温调节（AC/03）
            case "ac03":
                // 调节阀: 写目标调节值（AC/04）
            case "ac04":
                // 调节阀: 写开启/结束计量日期（A0/19）
            case "a019":
                // 调节阀: 写阀门开度上下限（A0/28）
            case "a028":
                // 锁闭阀: 写充值信息（AC/05）
            case "ac05":
                // 锁闭阀: 充值信息清除（AC/07）
            case "ac07":
                // 锁闭阀: 写充值水量信息（A1/01）
            case "a101":
                // 锁闭阀: 撤销某次水量充值（A1/02）
            case "a102":
                resultMap = new HashMap<>(1);

                // 更新命令结果状态
                resultMap.put("statusCode", Constant.SYMBOL_00);
                break;
            // 锁闭阀: 读清洗阀门周期（A0/2D）
            case "a02d":
                resultMap = new HashMap<>(2);
                cleanCycleLow = CodeUtil.byteToHexString(byteBuf.readByte());
                cleanCycleHigh = CodeUtil.byteToHexString(byteBuf.readByte());
                resultMap.put("cleanCycle", ComUtil.safeInt(cleanCycleHigh + cleanCycleLow));

                // 保存终端配置参数
//                utilityService.saveTerminalNBConfigParam4Lock(terminalId, resultMap);

                // 更新命令结果状态
                resultMap.put("statusCode", Constant.SYMBOL_00);
                break;
            // 客户AB/01
            case "ab01":
                // 设置温度偏差（NBT200测温插座）
                if ("EN1434_9988".equals(protocolCode)) {
                    resultMap = new HashMap<>(2);
                    resultMap.put("temperatureDiff", byteBuf.readShortLE());
                }
                // 调节阀: 读调节阀所有配置参数
                else {
                    resultMap = new HashMap<>(15);

                    // 采暖季开始
                    startDay = CodeUtil.byteToHexString(byteBuf.readByte());
                    startMonth = CodeUtil.byteToHexString(byteBuf.readByte());
                    resultMap.put("heatSeasonStart", startMonth + "-" + startDay);
                    // 采暖季结束
                    endDay = CodeUtil.byteToHexString(byteBuf.readByte());
                    endMonth = CodeUtil.byteToHexString(byteBuf.readByte());
                    resultMap.put("heatSeasonEnd", endMonth + "-" + endDay);
                    // 开度上限
                    openDegreeUpperLow = CodeUtil.byteToHexString(byteBuf.readByte());
                    openDegreeUpperHigh = CodeUtil.byteToHexString(byteBuf.readByte());
                    resultMap.put("openDegreeUpper", ComUtil.safeInt(openDegreeUpperHigh + openDegreeUpperLow));
                    // 开度下限
                    openDegreeLowerLow = CodeUtil.byteToHexString(byteBuf.readByte());
                    openDegreeLowerHigh = CodeUtil.byteToHexString(byteBuf.readByte());
                    resultMap.put("openDegreeLower", ComUtil.safeInt(openDegreeLowerHigh + openDegreeLowerLow));
                    // 清洗周期
                    cleanCycleLow = CodeUtil.byteToHexString(byteBuf.readByte());
                    cleanCycleHigh = CodeUtil.byteToHexString(byteBuf.readByte());
                    resultMap.put("cleanCycle", ComUtil.safeInt(cleanCycleHigh + cleanCycleLow));
                    // 调节模式：0-面板控制；1-远程控制开度；2-回水温度控制开度；3-进回水温差控制开度
                    int adjustMode = byteBuf.readByte();
                    resultMap.put("adjustMode", adjustMode);
                    // 是否启用自动调平：0-启用；1-不启用
                    resultMap.put("autoAdjust", byteBuf.readByte());
                    // 目标调节值（BCD码）50%开度，调节模式不同含义不同，调节模式为00：此处无用；01：表目标开度；02：表目标温度；03：表目标温差
                    String adjustValueLow = CodeUtil.byteToHexString(byteBuf.readByte());
                    String adjustValueHigh = CodeUtil.byteToHexString(byteBuf.readByte());
                    int adjustValue = ComUtil.safeInt(adjustValueHigh + adjustValueLow);
                    if (adjustMode == Constant.VALVE_ADJUST_MODE_1) {
                        resultMap.put("adjustValue", adjustValue);
                    } else if (adjustMode == Constant.VALVE_ADJUST_MODE_2 || adjustMode == Constant.VALVE_ADJUST_MODE_3) {
                        resultMap.put("adjustValue", adjustValue * 0.01);
                    }
                    // 调节周期（BCD码）
                    String adjustCycleLow = CodeUtil.byteToHexString(byteBuf.readByte());
                    String adjustCycleHigh = CodeUtil.byteToHexString(byteBuf.readByte());
                    resultMap.put("adjustCycle", ComUtil.safeInt(adjustCycleHigh + adjustCycleLow));
                    // 调节死区（BCD码）
                    String adjustDeadZoneLow = CodeUtil.byteToHexString(byteBuf.readByte());
                    String adjustDeadZoneHigh = CodeUtil.byteToHexString(byteBuf.readByte());
                    resultMap.put("adjustDeadZone", ComUtil.safeDouble(ComUtil.safeInt(adjustDeadZoneHigh + adjustDeadZoneLow)) * 0.01);
                    // 系数P
                    String coefficientPLow = CodeUtil.byteToHexString(byteBuf.readByte());
                    String coefficientPHigh = CodeUtil.byteToHexString(byteBuf.readByte());
                    resultMap.put("coefficientP", ComUtil.safeDouble(ComUtil.safeInt(coefficientPHigh + coefficientPLow)) * 0.01);
                    // 系数I
                    String coefficientILow = CodeUtil.byteToHexString(byteBuf.readByte());
                    String coefficientIHigh = CodeUtil.byteToHexString(byteBuf.readByte());
                    resultMap.put("coefficientI", ComUtil.safeDouble(ComUtil.safeInt(coefficientIHigh + coefficientILow)) * 0.01);
                    // 系数D
                    String coefficientDLow = CodeUtil.byteToHexString(byteBuf.readByte());
                    String coefficientDHigh = CodeUtil.byteToHexString(byteBuf.readByte());
                    resultMap.put("coefficientD", ComUtil.safeDouble(ComUtil.safeInt(coefficientDHigh + coefficientDLow)) * 0.01);
                    // 调节比例
                    String adjustRatioLow = CodeUtil.byteToHexString(byteBuf.readByte());
                    String adjustRatioHigh = CodeUtil.byteToHexString(byteBuf.readByte());
                    resultMap.put("adjustRatio", ComUtil.safeInt(adjustRatioHigh + adjustRatioLow));

                    // 保存终端配置参数
//                    utilityService.saveTerminalNBConfigParam4Adjust(terminalId, resultMap);
                }

                // 更新命令结果状态
                resultMap.put("statusCode", Constant.SYMBOL_00);
                break;
            // 调节阀: 读开启/结束计量日期（A0/1A）
            case "a01a":
                resultMap = new HashMap<>(3);

                // 开启日期
                startDay = CodeUtil.byteToHexString(byteBuf.readByte());
                startMonth = CodeUtil.byteToHexString(byteBuf.readByte());
                resultMap.put("startDate", startMonth + "-" + startDay);
                // 结束日期
                endDay = CodeUtil.byteToHexString(byteBuf.readByte());
                endMonth = CodeUtil.byteToHexString(byteBuf.readByte());
                resultMap.put("endDate", endMonth + "-" + endDay);

                // 更新命令结果状态
                resultMap.put("statusCode", Constant.SYMBOL_00);
                break;
            // 调节阀: 读阀门开度上下限（A0/29）
            case "a029":
                resultMap = new HashMap<>(3);

                // 开度上限
                openDegreeUpperLow = CodeUtil.byteToHexString(byteBuf.readByte());
                openDegreeUpperHigh = CodeUtil.byteToHexString(byteBuf.readByte());
                resultMap.put("openDegreeUpper", ComUtil.safeInt(openDegreeUpperHigh + openDegreeUpperLow));
                // 开度下限
                openDegreeLowerLow = CodeUtil.byteToHexString(byteBuf.readByte());
                openDegreeLowerHigh = CodeUtil.byteToHexString(byteBuf.readByte());
                resultMap.put("openDegreeLower", ComUtil.safeInt(openDegreeLowerHigh + openDegreeLowerLow));

                // 更新命令结果状态
                resultMap.put("statusCode", Constant.SYMBOL_00);
                break;
            // 锁闭阀: 读充值信息（AB/05）
            case "ab05":
                resultMap = new HashMap<>(6);

                // 充值控制模式
                resultMap.put("controlMode", CodeUtil.byteToHexString(byteBuf.readByte()));
                // 充值流水号
                String controlSerialNo1 = CodeUtil.byteToHexString(byteBuf.readByte());
                String controlSerialNo2 = CodeUtil.byteToHexString(byteBuf.readByte());
                String controlSerialNo3 = CodeUtil.byteToHexString(byteBuf.readByte());
                String controlSerialNo4 = CodeUtil.byteToHexString(byteBuf.readByte());
                resultMap.put("controlSerialNo", ComUtil.safeInt(controlSerialNo4 + "" + controlSerialNo3 + "" + controlSerialNo2 + "" + controlSerialNo1));
                // 充值时间段开始
                String controlDateStart1 = CodeUtil.byteToHexString(byteBuf.readByte());
                String controlDateStart2 = CodeUtil.byteToHexString(byteBuf.readByte());
                String controlDateStart3 = CodeUtil.byteToHexString(byteBuf.readByte());
                resultMap.put("controlDateStart", (controlDateStart3 + "-" + controlDateStart2 + "-" + controlDateStart1));
                // 充值时间段结束
                String controlDateEnd1 = CodeUtil.byteToHexString(byteBuf.readByte());
                String controlDateEnd2 = CodeUtil.byteToHexString(byteBuf.readByte());
                String controlDateEnd3 = CodeUtil.byteToHexString(byteBuf.readByte());
                resultMap.put("controlDateEnd", (controlDateEnd3 + "-" + controlDateEnd2 + "-" + controlDateEnd1));
                // 充值小时
                String controlAvailableTime1 = CodeUtil.byteToHexString(byteBuf.readByte());
                String controlAvailableTime2 = CodeUtil.byteToHexString(byteBuf.readByte());
                String controlAvailableTime3 = CodeUtil.byteToHexString(byteBuf.readByte());
                String controlAvailableTime4 = CodeUtil.byteToHexString(byteBuf.readByte());
                resultMap.put("controlAvailableTime", ComUtil.safeInt(controlAvailableTime4 + "" + controlAvailableTime3 + "" + controlAvailableTime2 + "" + controlAvailableTime1));

                // 保存终端配置参数
//                utilityService.saveTerminalNBConfigParam4Lock(terminalId, resultMap);

                // 更新命令结果状态
                resultMap.put("statusCode", Constant.SYMBOL_00);
                break;
            // 锁闭阀: 查询水量充值记录（A2/01）
            case "a201":
                resultMap = new HashMap<>(2);

                // 充值水量记录
                List<Map<String, Object>> recordMapList = new ArrayList<>(4);
                Map<String, Object> recordMap;
                StringBuilder sbRechargeSerialNumber;
                for (int i = 0; i < 4; i++) {
                    recordMap = new HashMap<>(2);
                    sbRechargeSerialNumber = new StringBuilder();
                    for (int j = 0; j < 20; j++) {
                        String hexStr = CodeUtil.byteToHexString(byteBuf.readByte());
                        if (Constant.SYMBOL_00.equals(hexStr)) {
                            byteBuf.skipBytes(20 - j - 1);
                            break;
                        }
                        sbRechargeSerialNumber.append(CodeUtil.hexStringToAsciiString(hexStr));
                    }
                    recordMap.put("充值序列号", sbRechargeSerialNumber);
                    recordMap.put("充值水量", byteBuf.readFloatLE());

                    recordMapList.add(recordMap);
                }
                resultMap.put("rechargeRecordList", recordMapList);

                // 更新命令结果状态
                resultMap.put("statusCode", Constant.SYMBOL_00);
                break;
            default:
                resultMap = null;

                log.error("processData: dataSymbol[{}] match fail", dataSymbol);
        }

        return resultMap;
    }
}
